home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 04 - 1988 / 04.01 Jan 88 / Downloader Source / Downloader.c next >
Encoding:
C/C++ Source or Header  |  1987-07-13  |  17.9 KB  |  958 lines  |  [TEXT/KAHL]

  1. /*
  2.  
  3.     PS PRINT
  4.     A PostScript Downloader written by Nicholas Pavkovic
  5.     © Perimeter, 1987.
  6.     Portions copyrighted by THINK Technologies, Inc., and Apple Computer, Inc.
  7.     No restrictions on non-commercial distribution of program (not source).
  8.     
  9.     PERIMETER
  10.     1608 North Milwaukee Avenue
  11.     Chicago Illinois 60647
  12.     312 . 278 . 9509
  13.     
  14. */
  15.  
  16. #include <MacTypes.h>
  17. #include <QuickDraw.h>
  18. #include <EventMgr.h>
  19. #include <StdFilePkg.h>
  20.  
  21. /*
  22.     Libraries linked:
  23.     MacTraps
  24.     sprintf/sscanf
  25. */
  26.  
  27. /* FileMgr.h Defs (don’t need whole file) */
  28.  
  29. #define fnfErr -43
  30. #define eofErr -39
  31. extern int FSFCBLen : 0x3F6;
  32. extern int BootDrive : 0x210;
  33. extern int SysMap : 0xA58;
  34.  
  35. /* WindowMgr.h (don’t need whole file) */
  36.  
  37. #define NewWindow        (long) NewWindow
  38. #define dBoxProc 1
  39.  
  40. /* General */
  41.  
  42. #define True 1
  43. #define False 0
  44. #define Success 0
  45. #define Failure -1
  46. #define Fails == -1
  47. #define NULL                0L
  48.  
  49.  
  50. /* Fall-through functions */
  51.  
  52. #define IssueRead()                    if( issueread() Fails ) return( Failure )
  53. #define CheckIfCancelled()        if( checkifcancelled() Fails ) return( Failure )
  54. #define DisplayStatus()                if( displaystatus() Fails ) return( Failure )
  55. #define OpenLChannel()            if( openlchannel()  Fails ) return( Failure)
  56. #define PostMessage(x, y )        if( postmessage(x, y) Fails ) return( Failure )
  57.  
  58. /* PostMessage selectors */
  59.  
  60. #define FromPrinter                    1
  61. #define FromProgram                0
  62.  
  63. #define SIMPLEALERT                1000
  64.  
  65. /* File-related */
  66.  
  67. int                                FErr;
  68. int                                FileRef;
  69. SFReply                        UserReply;
  70. SFTypeList                Fylz;
  71. Point                            SFPoint;
  72. char                            *OpenName;
  73. char                            NullString;
  74.  
  75. EventRecord            theEvent;
  76. Handle                        DummyHand1;
  77. Rect                            DummyRect;
  78. long                            DummyType;
  79.  
  80. /* Windows */
  81.  
  82. long                            PrintWinPtr;
  83. long                            DirectWin;
  84.  
  85. /* Please include InfoWin if you compile and distribute the program */
  86.  
  87. long                            InfoWin;
  88.  
  89. char                            *InfoString = "A PostScript Downloader written by Nicholas Pavkovic\r\r© Perimeter 1987.\rPortions © THINK and Apple Computer, Inc.\rNon-commercial distribution is permitted.\
  90. \r\rPERIMETER\r1608 North Milwaukee Avenue\rChicago Illinois 60647\r312 . 278 . 9509\r \
  91. Developers of LaserLabels™ and QuickScript™\r\r• Click on the mouse to continue."; 
  92.  
  93. /* PAP globals  */
  94.  
  95. typedef struct
  96. {
  97.     long int        systemstuff;
  98.     char        statusstr[256];
  99. } papstatusrec, *papstatusptr;
  100.  
  101.  
  102. Handle            pap;
  103. long                papaddr;
  104.  
  105. int                FlowQuantum;
  106.  
  107. long unsigned                LaserNode;
  108. int                                     OpenState;
  109. int                                     WriteState;
  110. int                                     ReadState;
  111.  
  112. int                                     ConnectId;
  113.  
  114. int                                     WriteEof;
  115. int                                     ReadEof;
  116.  
  117. char                                ReadSpace[4096];
  118. char                                 *WriteBuffer;
  119.  
  120. int                                     WriteSize;
  121. int                                     ReadSize;
  122.  
  123. char                                *LaserName;
  124. Handle                            LaserHand;
  125. char                                LaserNameBuff[64];
  126.  
  127. papstatusrec                     LaserStatus;
  128.  
  129. char                                VirtualPage[4096];
  130. char                                MessageBuff[256];
  131.  
  132. Handle                            FeedbackHandle;
  133. long                                FHandleSize;
  134.  
  135. long                                LastStatusDisplay;
  136.  
  137.  
  138. /*
  139.     SimpleAlert:
  140.     Implements a general alert used for
  141.     most of the terminal error messages.
  142. */
  143.  
  144. SimpleAlert( m0 )
  145. char    *m0;
  146. {
  147.     ParamText( m0, 0L, 0L, 0L );
  148.     NoteAlert( SIMPLEALERT, 0L ) ;
  149. }
  150.  
  151. /*
  152.     SFDFilter:
  153.     Filter function for Standard File Dialog.
  154.     Makes the “Open” button context sensitive
  155.     and gives it a heavy outline.
  156. */
  157.  
  158. pascal Boolean SFDFilter( dlog, event, itemhit )
  159. long        dlog;
  160. EventRecord    *event;
  161. int                *itemhit;
  162. {
  163.     if ( event->what == activateEvt && event->modifiers & activeFlag )
  164.     {
  165.         GetDItem( dlog, getOpen, &DummyType, &DummyHand1, &DummyRect );
  166.         SetCTitle( DummyHand1, OpenName );
  167.         
  168.         PenSize(3, 3);
  169.         InsetRect( &DummyRect, -4, -4 );
  170.         FrameRoundRect( &DummyRect, 16, 16);
  171.         PenSize(1,1);
  172.     };
  173.     return( False );
  174. }
  175.  
  176. /*
  177.     displaystatus:
  178.     Checks and display status every second,
  179.     even if routine is called more frequently.
  180. */
  181.     
  182. displaystatus()
  183. {
  184.     if( TickCount() - LastStatusDisplay > 60 )
  185.     {
  186.         PapStatus();
  187.         PostMessage( &LaserStatus.statusstr, FromPrinter );
  188.         LastStatusDisplay = TickCount();
  189.     };
  190.     CheckIfCancelled();
  191. }
  192.  
  193. /*
  194.     Directions:
  195.     Display text in the directions window.
  196. */
  197.  
  198. Directions( text )
  199. char    *text;
  200. {
  201.     DummyRect.top = 10;
  202.     DummyRect.left = 10;
  203.     DummyRect.right = 342;
  204.     DummyRect.bottom = 80;
  205.     
  206.     SetPort( DirectWin );
  207.     MoveTo( 10, 16 );
  208.     TextBox( &text[1], (long) text[0], &DummyRect, 0 );
  209. }
  210.  
  211. main()
  212. {
  213.     char *source, *dest;
  214.     int counter;
  215.     int sysVRef;
  216.  
  217.     InitGraf(&thePort);
  218.     InitFonts();
  219.     InitWindows();
  220.     TEInit();
  221.     InitDialogs(0L);
  222.     FlushEvents(everyEvent, 0);
  223.     InitCursor();
  224.     
  225.     /*
  226.         Read PAP routines into memory.
  227.         OpenResFile uses PMSP; we need only to find boot drive.
  228.         See Tech Note #77 for details.
  229.     */
  230.     
  231.     if( FSFCBLen )
  232.     {
  233.         FErr = GetVRefNum( SysMap, &sysVRef );
  234.     }
  235.     else
  236.     {
  237.         sysVRef = BootDrive;
  238.     };
  239.     SetVol( &NullString, sysVRef );
  240.     
  241.         
  242.     
  243.     FErr = OpenResFile("\pLaserWriter");
  244.  
  245.     if( FErr == -1 )
  246.     {
  247.         SysBeep(1);
  248.         SimpleAlert( "\pThe LaserWriter file could not be found or couldn’t be opened. Returning to Finder.");
  249.         return;
  250.     };
  251.     
  252.     /* Read the PAP code into memory */
  253.     
  254.     if ( (  pap = GetResource( 'PDEF', 10 ) ) == NULL || ResError() ) 
  255.     {
  256.         SysBeep(1);
  257.         SimpleAlert( "\pThe PAP routines could not be loaded. Returning to Finder.");
  258.         if( FErr != -1 ) CloseResFile( FErr );
  259.         return;
  260.     };
  261.         
  262.     /* Detach PAP */
  263.     
  264.     HLock(pap);
  265.     DetachResource(pap);
  266.     papaddr = (long) *pap;
  267.     
  268.     /* Read printer name from LaserWriter file */
  269.     
  270.     if ( (  LaserHand = GetResource( 'PAPA', -8192 ) ) == NULL || ResError() )
  271.     {
  272.         SysBeep(1);
  273.         SimpleAlert( "\pThe LaserWriter name could not be read. Returning to Finder.");
  274.         return;
  275.     };
  276.         
  277.     /* Create a C string version of the printer name (for messages) and place it into LaserNameBuff  */
  278.  
  279.     HLock( LaserHand );
  280.     DetachResource( LaserHand );
  281.     LaserName = *LaserHand;
  282.     
  283.     /*
  284.         Copy the printer name into LaserNameBuff,
  285.         a C string version used for messages to user.
  286.     */
  287.     
  288.     source = (char *) LaserName + 1;
  289.     dest = LaserNameBuff;
  290.     counter = (int) *LaserName;
  291.     while( counter-- ) *dest++ = *source++;
  292.     *dest = 0;
  293.     
  294.     /* Done with LaserWriter file */
  295.     
  296.     CloseResFile( FErr );
  297.  
  298.     /* About PS PRINT... */
  299.  
  300.     DummyRect.left = 62;
  301.     DummyRect.top = 36;
  302.     DummyRect.bottom = 318;
  303.     DummyRect.right = 446;
  304.     InfoWin = NewWindow( 0L, &DummyRect, &NullString, 0xFF, dBoxProc, -1L, False, 0L );
  305.     SetPort( InfoWin );
  306.     TextFace( condense );
  307.     TextFont( 0 );
  308.  
  309.     MoveTo( 10, 36 );
  310.     DrawString( "\pPS PRINT" );
  311.     
  312.     PenPat( gray );
  313.     MoveTo( 64, 26 );
  314.     PenSize( 1, 12 );
  315.     LineTo( 362, 26 );
  316.     PenNormal();
  317.     
  318.     TextFont( 1 );
  319.  
  320.     DummyRect.top = 46;
  321.     DummyRect.left = 10;
  322.     DummyRect.bottom = 282;
  323.     DummyRect.right = 362;
  324.     
  325.     TextBox( InfoString, 314L, &DummyRect, -1 );
  326.  
  327.     while( GetNextEvent( everyEvent, &theEvent) == 0 || theEvent.what != mouseDown ) SystemTask(); 
  328.  
  329.     DisposeWindow( InfoWin );
  330.  
  331.     /* Setup instruction window. */
  332.     
  333.     DummyRect.left = 80;
  334.     DummyRect.top = 36;
  335.     DummyRect.bottom = 90;
  336.     DummyRect.right = 428;
  337.  
  338.     /*
  339.         Technically, there’s no reason that the directions window should be a dialog,
  340.         but if it’s set up as a normal window, the SFD won’t redisplay the file list 
  341.         when a new disk is inserted. Try it. Anyone know why?
  342.     */
  343.     
  344.     DirectWin = (long) NewDialog( 0L, &DummyRect, &NullString, 0xFF, dBoxProc, 0L, 0, 0L, 0L );
  345.  
  346.     SetPort( DirectWin );
  347.     TextFace( condense );
  348.     TextFont( 0 );
  349.  
  350.     FeedbackHandle = NewHandle( 0 );
  351.     
  352.     if( FeedbackHandle == 0 || MemError() )
  353.     {
  354.         SimpleAlert( "\pCan’t Allocate Feedback Handle. Returning to Finder." );
  355.         return;
  356.     };
  357.     
  358.     SFPoint.v = 108;
  359.  
  360.     /* Download loop */
  361.     
  362.     while( 1 )
  363.     {
  364.         SetHandleSize( FeedbackHandle, 0L );
  365.         FHandleSize = 0;
  366.         
  367.         /* Select file to download */
  368.  
  369.         Directions( "\p• Select a file to download, or\r• Click on Cancel to transfer or return to the Finder" );
  370.         SFPoint.h = 80;
  371.         Fylz[0] = 'TEXT';
  372.         OpenName = "\pDownload";
  373.         SFPGetFile( SFPoint, &NullString,  0L, 1, Fylz, 0L, &UserReply, -4000, SFDFilter  );
  374.  
  375.         /* If file selected, download it, otherwise transfer */
  376.         
  377.         if ( UserReply.good )
  378.         {
  379.             TextDownload( &UserReply.fName, UserReply.vRefNum );
  380.         }
  381.         else
  382.         {
  383.             Directions( "\p• Select an application to transfer to, or\r• Click on Cancel to return to the Finder" );
  384.             Fylz[0] = 'APPL';
  385.             OpenName = "\pTransfer";
  386.             SFPGetFile( SFPoint, &NullString,  (ProcPtr) 0, 1, Fylz, 0L, &UserReply, -4000, SFDFilter);
  387.         
  388.             DisposDialog( DirectWin );
  389.  
  390.             /* If user cancels transfer, return to Finder */
  391.             
  392.             if ( !UserReply.good ) return;
  393.             
  394.             MessageBuff[0] = 0;
  395.             SetVol( &MessageBuff, UserReply.vRefNum ); 
  396.             Launch( 0, &UserReply.fName );
  397.         };
  398.  
  399.         /* If feedback has been received, save it to a file. */
  400.         
  401.         if( FHandleSize )
  402.         {
  403.             Directions( "\p• Enter a filename to save the printer feedback, or\r• Click on Cancel to continue" );
  404.  
  405.             TryAgain:
  406.             
  407.             SFPoint.h = 104;
  408.             SFPutFile( SFPoint, "\pSave the feedback as:", "\pFeedback", 0L, &UserReply );
  409.     
  410.             /* If user cancels, loop to downloading code */
  411.             
  412.             if ( !UserReply.good ) continue;
  413.  
  414.             FErr = FSOpen( &UserReply.fName, UserReply.vRefNum, &FileRef );
  415.             
  416.             /* If the specified file doesn’t exist, create it */
  417.             
  418.             if( FErr == fnfErr )
  419.             {
  420.                 SetVol( &NullString, UserReply.vRefNum);
  421.                 FErr = Create( &UserReply.fName, 0, 'EDIT', 'TEXT' );
  422.                 FErr = FSOpen( &UserReply.fName, UserReply.vRefNum, &FileRef );
  423.             };
  424.  
  425.             if( FErr != 0 )
  426.             {
  427.                 PtoCstr( &UserReply.fName );
  428.                 sprintf( &MessageBuff,"The file you requested, “%s”, is not currently available. Error: %d", &UserReply.fName, FErr );
  429.                 CtoPstr( &MessageBuff );
  430.                 SimpleAlert( &MessageBuff );
  431.                 goto TryAgain;
  432.             };
  433.             
  434.             HLock( FeedbackHandle );
  435.             DummyType = FHandleSize;
  436.             SetFPos( FileRef, 1, 0L );
  437.             FSWrite( FileRef, &DummyType, *FeedbackHandle );
  438.             SetEOF( FileRef, DummyType );
  439.             FSClose( FileRef );
  440.             HUnlock( FeedbackHandle );
  441.         };
  442.     };
  443. }
  444.  
  445. openlchannel()
  446. {
  447.  
  448.     long CurrentTime, StartOpening;
  449.  
  450.     Directions("\p• Press \021. (Command-Period) to cancel the download");
  451.  
  452.     /* Set up print window. */
  453.     
  454.     DummyRect.top = 108;
  455.     DummyRect.left = 80;
  456.     DummyRect.bottom = 296;
  457.     DummyRect.right = 428;
  458.     
  459.     PrintWinPtr =     NewWindow( 0L, &DummyRect, NullString, 0xFF, dBoxProc, -1L, False, 0L );
  460.     SetPort( PrintWinPtr );
  461.     TextFont( 0 );
  462.     TextFace( condense );
  463.     
  464.     PenSize( 1, 1 );
  465.     PenPat( black );
  466.     
  467.     MoveTo( 10, 24 );
  468.     LineTo( 12, 24 );
  469.     MoveTo( 14, 28 );
  470.     DrawString( "\pProgram" );
  471.     Move( 2, -4 );
  472.     LineTo( 338, 24 );
  473.     LineTo( 338, 86 );
  474.     LineTo( 10, 86 );
  475.     LineTo( 10, 24 );
  476.     
  477.     MoveTo( 10, 108 );
  478.     LineTo( 12, 108 );
  479.     MoveTo( 14, 112 );
  480.     DrawString( "\pPrinter" );
  481.     Move( 2, -4 );
  482.     LineTo( 338, 108 );
  483.     LineTo( 338, 170 );
  484.     LineTo( 10, 170 );
  485.     LineTo( 10, 108 );
  486.  
  487.     TextFont( 1 );
  488.     
  489.     /*  Open connection to server   */
  490.  
  491.     sprintf( &MessageBuff, "Looking for printer “%s.”", &LaserNameBuff );
  492.     CtoPstr( &MessageBuff );
  493.     PostMessage( &MessageBuff, FromProgram );
  494.     
  495.     FlowQuantum = 8;
  496.     ConnectId = 0;
  497.     
  498.     if ( PapOpen() ) 
  499.     {
  500.         NoPrinter();
  501.         return( Failure );
  502.     };
  503.  
  504.     sprintf( &MessageBuff, "Establishing connection with “%s.”", &LaserNameBuff );
  505.     CtoPstr( &MessageBuff );
  506.     PostMessage( &MessageBuff, FromPrinter );
  507.     
  508.     StartOpening = TickCount();
  509.     
  510.     while( OpenState > 0 ) 
  511.     {
  512.         DisplayStatus();
  513.  
  514.         CurrentTime = TickCount();
  515.         if( CurrentTime - StartOpening > 1800 )
  516.         {
  517.             NoPrinter();
  518.             return( Failure );
  519.         };
  520.         
  521.         CheckIfCancelled();
  522.     };
  523.     
  524.     if ( OpenState < 0 )
  525.     {
  526.         NoPrinter();
  527.         return( Failure );
  528.     };
  529.         
  530.     PostMessage( "\pConnection established.", FromProgram );
  531.     
  532.     ReadState = 0;
  533.     WriteState = 0;
  534.     ReadEof = 0;
  535.     WriteEof = 0;
  536.     ReadSize = 0;
  537.     WriteSize = 0;
  538.     
  539.     return( Success );
  540. }
  541.     
  542. issueread()
  543. {
  544.         long oldsize;
  545.         char *fbptr, *readptr;
  546.         
  547.         if ( ReadState <= 0 )
  548.         {
  549.             /* Negative ReadState indicates communications failure */
  550.             
  551.             if ( ReadState < 0 )
  552.             {
  553.                 EndPCom();
  554.                 return( Failure );
  555.             };
  556.                 
  557.             /*
  558.                 ReadState == 0 => successful read.
  559.                 ReadSize>0 => There’s feedback.
  560.             */
  561.             
  562.             if ( ReadSize > 0 )
  563.             {
  564.                 
  565.                 SysBeep(1);
  566.  
  567.                 /*
  568.                     Feedback messages use ASCII 10 (linefeed) instead of
  569.                     ASCII 13 (carriage return). Convert them and display.
  570.                 */
  571.                 
  572.                 readptr = &ReadSpace[ ReadSize - 1];
  573.                 if( *readptr == 10 ) *readptr = 13;
  574.                 *(++readptr) = '\0';
  575.                 CtoPstr(&ReadSpace);
  576.                 PostMessage( &ReadSpace, FromPrinter  );
  577.                 Delay( (long int) 150, &DummyHand1);
  578.  
  579.                 /* Update the feedback handle’s size and copy feedback. */
  580.  
  581.                 oldsize = FHandleSize;
  582.                 FHandleSize += ReadSize;
  583.                 SetHandleSize( FeedbackHandle, FHandleSize );
  584.                 
  585.                 if( MemError() == noErr )
  586.                 {
  587.                     readptr = &ReadSpace[1];
  588.                     fbptr = (char *) *FeedbackHandle + oldsize;
  589.                     while( ReadSize-- ) *fbptr++ = *readptr++;
  590.                 };
  591.             };
  592.             
  593.             /* Issue another read */
  594.             
  595.             if (PapRead() )
  596.             {
  597.                 EndPCom();
  598.                 return( Failure );
  599.             };
  600.             
  601.             CheckIfCancelled();
  602.         }
  603.         else
  604.         {
  605.             /* Since ReadState > 0, last read has not ended yet */
  606.             
  607.             DisplayStatus();
  608.         };
  609.  
  610.         return( Success );
  611. }
  612.         
  613. CloseLChannel()
  614. {
  615.  
  616.     IssueRead();
  617.  
  618.     /*  set end-of-file  */
  619.     WriteEof = 1;
  620.     
  621.     /* Send empty buffer */
  622.     WriteBuffer = "";
  623.     WriteSize = 0;
  624.     
  625.     if ( PapWrite() )
  626.     {
  627.         EndPCom();
  628.         return( Failure );
  629.     };
  630.         
  631.     /* Wait for printer to indicate that processing is over */
  632.     
  633.     while ( ReadEof == 0) IssueRead();    
  634.     
  635.     PapClose();
  636.     PapUnload();
  637.     DisposeWindow( PrintWinPtr );
  638.     return( Success );
  639. }
  640.  
  641. /*
  642.     EndPCom:
  643.     Closes connection immediately.
  644. */
  645.  
  646. EndPCom()
  647. {
  648.     PapClose();
  649.     PapUnload();
  650.     DisposeWindow( PrintWinPtr );
  651.     sprintf( &MessageBuff, "Communication with the printer “%s” has ended.", &LaserNameBuff );
  652.     CtoPstr( &MessageBuff );
  653.     SimpleAlert( &MessageBuff );
  654. }
  655.  
  656. /*
  657.     postmessage:
  658.     Displays messages from printer and program
  659.     in PrintWin.
  660. */
  661.     
  662. postmessage( s, source )
  663. char        *s;
  664. int            source;
  665. {
  666.  
  667.     DummyRect.left = 13;
  668.     DummyRect.right = 335;
  669.  
  670.     if( source == FromProgram )
  671.     {
  672.         DummyRect.top = 35;
  673.         DummyRect.bottom = 83;
  674.     }
  675.     else
  676.     {    
  677.         DummyRect.top = 119;
  678.         DummyRect.bottom = 167;
  679.     };
  680.     
  681.     TextBox( &s[1], (long) s[0], &DummyRect, 0 );
  682.     
  683.     CheckIfCancelled();
  684.     return( Success );
  685. }
  686.  
  687. /*
  688.     checkifcancelled:
  689.     Checks if user has cancelled the
  690.     download with Command-Period.
  691. */
  692.     
  693. checkifcancelled()
  694. {
  695.     if( GetNextEvent( everyEvent, &theEvent) == 0 ) 
  696.     {
  697.         SystemTask();
  698.         return( Success );
  699.     };
  700.     
  701.     if( theEvent.what == keyDown &&
  702.             theEvent.modifiers & cmdKey &&
  703.                 (theEvent.message & charCodeMask ) == '.' )
  704.     {
  705.         EndPCom();
  706.         return( Failure );
  707.     };
  708. }
  709.  
  710. /*
  711.     TextDownload:
  712.     Downloads the specified file to the printer
  713. */
  714.     
  715. TextDownload( FFileName, Vnum )
  716. Str255    *FFileName;
  717. int        Vnum;
  718. {
  719.     long        ItemsRead;
  720.     long        FileSize, Remaining;
  721.     Str255        WorkingMessage;
  722.     
  723.     OpenLChannel();
  724.     
  725.     FErr = FSOpen( FFileName, Vnum, &FileRef );
  726.     PtoCstr( FFileName );
  727.     
  728.     if ( FErr != noErr )
  729.     {
  730.         CloseLChannel();
  731.         sprintf( &MessageBuff, "Sorry, the file “%s” could not be opened. Error: %d", FFileName, FErr );
  732.         CtoPstr( &MessageBuff );
  733.         SimpleAlert( &MessageBuff );
  734.         return( Failure );
  735.     };
  736.     
  737.     GetEOF( FileRef, &FileSize );
  738.     Remaining = FileSize;
  739.     
  740.     while( Remaining )
  741.     {
  742.         sprintf( &WorkingMessage, "Downloading “%s”\rComplete: %ld%%", FFileName, 100 - ((Remaining * 100 )/FileSize) );
  743.         CtoPstr( &WorkingMessage );
  744.         PostMessage( &WorkingMessage, FromProgram );
  745.         
  746.         ItemsRead = 4096;
  747.         
  748.         FErr = FSRead( FileRef, &ItemsRead, &VirtualPage);
  749.         
  750.         if ( ItemsRead == 0 && FErr != eofErr )
  751.         {
  752.             CloseLChannel();
  753.             goto ErrorExit;
  754.         }
  755.         else if ( FErr == eofErr )
  756.         {
  757.             WriteSize = (int) ItemsRead;
  758.             if( sendtoprinter( VirtualPage, (int) ItemsRead ) Fails ) goto ErrorExit;
  759.             FSClose( FileRef );
  760.             sprintf( &MessageBuff, "“%s” has been downloaded.", FFileName, FileRef );
  761.             CtoPstr( &MessageBuff );
  762.             PostMessage( &MessageBuff, FromProgram );
  763.             CloseLChannel();
  764.             return( Success );
  765.         };
  766.         
  767.         if( sendtoprinter( VirtualPage, (int) ItemsRead ) Fails ) goto ErrorExit;
  768.         Remaining -= ItemsRead;
  769.     };
  770.  
  771.     ErrorExit:
  772.     
  773.         FSClose( FileRef );
  774.         sprintf( &MessageBuff, "Sorry, the file “%s” could not be downloaded.", FFileName );
  775.         CtoPstr( &MessageBuff );
  776.         SimpleAlert( &MessageBuff );
  777.         return( Failure );
  778. }
  779.  
  780. /*
  781.     sendtoprinter:
  782.     General downloading routine (also handles buffers > 4096 bytes)
  783. */
  784.  
  785. sendtoprinter( bffer, bffsize )
  786.  char    *bffer;
  787.  int        bffsize;
  788.  {
  789.      register char    *bffptr;
  790.  
  791.       bffptr = bffer;
  792.       
  793.      while( bffsize > 0)
  794.      {
  795.      
  796.          if( bffsize > 4096 )
  797.          {
  798.              WriteSize = 4096;
  799.          }
  800.          else
  801.          {
  802.              WriteSize = bffsize;
  803.          };
  804.  
  805.          WriteBuffer = bffptr;
  806.  
  807.         IssueRead();                        
  808.  
  809.         if ( PapWrite() ) 
  810.         {
  811.             EndPCom();
  812.             return( Failure );
  813.         };
  814.     
  815.         CheckIfCancelled();
  816.  
  817.         /*
  818.             Issue reads to the printer while the
  819.             write is processing.
  820.         */
  821.         
  822.         while ( WriteState > 0  ) IssueRead();    
  823.     
  824.         if ( WriteState < 0 )                    
  825.         {
  826.             EndPCom();
  827.             return( Failure );
  828.         };    
  829.     
  830.         bffsize -= 4096;
  831.         bffptr += 4096;
  832.     };
  833.     
  834.     return( Success );
  835.  }
  836.  
  837. /*
  838.     NoPrinter:
  839.     Called if communications with printer can’t be established.
  840. */
  841.  
  842. NoPrinter()
  843. {
  844.     PapUnload();
  845.     DisposeWindow( PrintWinPtr );
  846.     sprintf( &MessageBuff, "Sorry, the printer “%s” is not currently available.", &LaserNameBuff );
  847.     CtoPstr( &MessageBuff );
  848.     SimpleAlert( &MessageBuff );
  849.     return( Failure );
  850. };
  851.  
  852. /*
  853.     PAP glue routines:
  854.     The routines start with a SUB command that makes room
  855.     for the result on the stack. Then they push the appropriate
  856.     PAP globals (allocated above) onto the stack, and jump to the
  857.     routine’s entry point, which is at some small offset from the
  858.     beginning of pap. When they return from the call, they pop
  859.     the result off the stack and put it into retval, which is returned.
  860. */
  861.  
  862. PapOpen()
  863. {
  864.     int retval;
  865.     
  866.     asm{
  867.         SUBQ.L    #2,A7
  868.         PEA    ConnectId
  869.         MOVE.L    LaserName,-(A7)
  870.         MOVE.W    FlowQuantum,-(A7)
  871.         PEA    LaserStatus
  872.         PEA    OpenState
  873.         MOVE.L    papaddr,A0
  874.         JSR    0(A0)
  875.         MOVE.W    (A7)+,retval
  876.     }
  877.     return( retval );
  878. }
  879.  
  880. PapRead()
  881. {
  882.     int retval;
  883.     
  884.     asm{
  885.         SUBQ.L    #2,A7
  886.          MOVE.W    ConnectId,-(A7)
  887.         PEA    ReadSpace
  888.         PEA    ReadSize
  889.         PEA    ReadEof    
  890.         PEA    ReadState
  891.         MOVE.L    papaddr,A0
  892.         JSR    4(A0)
  893.         MOVE.W    (A7)+,retval
  894.     }
  895.     return( retval );
  896. }
  897.  
  898. PapWrite()
  899. {
  900.  
  901.     int retval;
  902.     
  903.     asm{
  904.         SUBQ.L    #2,A7
  905.          MOVE.W    ConnectId,-(A7)
  906.         MOVE.L    WriteBuffer,-(A7)
  907.         MOVE.W    WriteSize,-(A7)
  908.         MOVE.W    WriteEof,-(A7)    
  909.         PEA    WriteState
  910.         MOVE.L    papaddr,A0
  911.         JSR    8(A0)
  912.         MOVE.W    (A7)+,retval
  913.     }
  914.     return( retval );
  915. }
  916.  
  917. PapStatus()
  918. {
  919.     int retval;
  920.     
  921.     asm{
  922.         SUBQ.L    #2,A7
  923.         MOVE.L    LaserName,-(A7)
  924.         PEA    LaserStatus
  925.         PEA    LaserNode
  926.         MOVE.L    papaddr,A0
  927.         JSR    12(A0)
  928.         MOVE.W    (A7)+,retval
  929.     }
  930.     return( retval );
  931. }
  932.  
  933. PapClose()
  934. {
  935.     int retval;
  936.     
  937.     asm{
  938.         SUBQ.L    #2,A7
  939.         MOVE.W    ConnectId,-(A7)
  940.         MOVE.L    papaddr,A0
  941.         JSR    16(A0)
  942.         MOVE.W    (A7)+,retval
  943.     }
  944.     return( retval );
  945. }
  946.  
  947. PapUnload()
  948. {
  949.     int retval;
  950.     
  951.     asm{
  952.         SUBQ.L    #2,A7
  953.         MOVE.L    papaddr,A0
  954.         JSR    20(A0)
  955.         MOVE.W    (A7)+,retval
  956.     }
  957.     return( retval );
  958. }